<template>
  <div class="app-login-page">
    <div class="app-login-page__login-part">
      <div class="app-login-page__login-logo">网易云</div>
      <n-card class="app-login-page__login-card" :content-style="showCaptchaLogin ? 'padding: 20px' : 'padding: 0'">
        <n-tabs
          v-if="!showCaptchaLogin"
          v-model:value="activeTabName"
          @update:value="onTabChange"
          class="card-tabs"
          type="card"
          size="large"
          animated
          pane-wrapper-style="margin: 0 -4px"
          pane-style="padding:20px; box-sizing: border-box;"
        >
          <n-tab-pane name="qrcodeLogin" tab="扫码登录">
            <div class="f fd-col ai-c mb-20">
              <div v-if="![LoginQrcodeCheckEnum.WAITSURE].includes(qrCheckCode)" class="f fd-col ai-c">
                <n-spin :show="!qrSrc || LoginQrcodeCheckEnum.AUTHSUCCESS === qrCheckCode" class="mt-40 mb-20">
                  <div class="qr-code-wrapper">
                    <q-r-canvas v-show="!!qrSrc" :options="{ resize: false, data: qrSrc }" :width="200" :height="200" class="w-200 h-200" />
                  </div>
                </n-spin>
                <p class="f-wt-b">请用网易云App扫码</p>
              </div>
              <div v-else-if="qrCheckCode === LoginQrcodeCheckEnum.WAITSURE" class="f fd-col ai-c mt-60">
                <n-icon size="36" color="green">
                  <check-circle-twotone />
                </n-icon>
                <p class="mt-10 f-sz-14">扫描成功！</p>
                <h4 class="mt-10 f-sz-14">请在手机上根据提示确认登录</h4>
              </div>
              <n-checkbox v-model:checked="loginRemember" class="mt-20">下次自动登录</n-checkbox>
            </div>
          </n-tab-pane>
          <n-tab-pane name="accountLogin" tab="账号登录">
            <n-form :model="formData" :rules="formRules" ref="formRef">
              <n-form-item label="手机号(+86)" path="phoneNumber">
                <n-input v-model:value="formData.phoneNumber" :allow-input="onlyAllowNumber" placeholder="请输入手机号" clearable />
              </n-form-item>
              <n-form-item label="密码" path="password">
                <n-input v-model:value="formData.password" type="password" show-password-on="click" placeholder="请输入密码">
                  <template #password-visible-icon>
                    <n-icon :size="16" :component="GlassesOutline" />
                  </template>
                  <template #password-invisible-icon>
                    <n-icon :size="16" :component="Glasses" />
                  </template>
                </n-input>
              </n-form-item>
              <n-button
                type="primary"
                block
                secondary
                strong
                :disabled="!formData.phoneNumber || (formData.phoneNumber && !isCnMobile(formData.phoneNumber))"
                @click="onSignIn"
              >
                登录
              </n-button>
              <div class="f jc-sb mt-10">
                <n-checkbox v-model:checked="loginRemember">下次自动登录</n-checkbox>
                <span class="captcha" @click="showCaptchaLogin = true">验证码登录</span>
              </div>
            </n-form>
          </n-tab-pane>
        </n-tabs>
        <n-form v-else :model="formData" :rules="formRules" ref="formRef">
          <n-form-item label="手机号(+86)" path="phoneNumber">
            <n-input v-model:value="formData.phoneNumber" :allow-input="onlyAllowNumber" placeholder="请输入手机号" clearable />
          </n-form-item>
          <n-form-item label="验证码" path="captcha">
            <n-input-group>
              <n-input v-model:value="formData.captcha" placeholder="请输入验证码"></n-input>
              <n-button
                :disabled="!formData.phoneNumber || countdownNumber > 0 || (formData.phoneNumber && !isCnMobile(formData.phoneNumber))"
                @click="captchaSent"
              >
                {{ countdownNumber > 0 ? `${countdownNumber}秒后重发` : '获取验证码' }}
              </n-button>
            </n-input-group>
          </n-form-item>
          <n-button
            type="primary"
            block
            secondary
            strong
            :disabled="!formData.phoneNumber || !formData.captcha || (formData.phoneNumber && !isCnMobile(formData.phoneNumber))"
            @click="onSignIn"
          >
            登录
          </n-button>
        </n-form>
        <template v-if="showCaptchaLogin" #header>
          <n-icon :component="LeftOutlined" size="24" :depth="2" @click="showCaptchaLogin = false"></n-icon>
        </template>
        <template v-if="showCaptchaLogin" #header-extra>
          <h4>短信验证</h4>
        </template>
      </n-card>
    </div>
  </div>
</template>
<script setup lang="ts">
  import { TabsInst, FormRules, FormItemRule, FormInst } from 'naive-ui';
  import { QRCanvas } from 'qrcanvas-vue';
  import { useGlobalProperties } from '@/hooks/useGlobalProperties';
  import { useApi } from '@/hooks/useApi';
  import { ResultEnum } from '@/enums/httpEnum';
  import { LoginQrcodeCheckEnum } from '@/enums/responseDateEnum';
  import { PageEnum } from '@/enums/pageEnum';
  import { CheckCircleTwotone, LeftOutlined } from '@vicons/antd';
  import { GlassesOutline, Glasses } from '@vicons/ionicons5';
  import { isCnMobile } from '@/utils/validate';
  import { useUserStoreOut } from '@/stores/modules/user';
  import { storage } from '@/utils';
  import { ACCESS_TOKEN } from '@/stores/mutation-types';
  import { useRouter } from 'vue-router';
  import md5 from 'js-md5';

  const emptyFormDataGenerator = () => ({
    phoneNumber: '',
    password: '',
    captcha: '',
  });

  const { $to, $message } = useGlobalProperties();
  const { login: loginApi } = useApi();
  const userStore = useUserStoreOut();
  const router = useRouter();

  let timer: any = null;
  const qrKey = ref<string>('');
  const qrSrc = ref<string>('');
  const userCookie = ref<string>('');
  const qrCheckCode = ref<number>(0);
  const countdownNumber = ref<number>(0);
  const activeTabName = ref<TabsInst>('qrcodeLogin');
  const loginRemember = ref<boolean>(false);
  const showCaptchaLogin = ref<boolean>(false);
  const formRef = ref<FormInst | null>(null);
  const formData = reactive(emptyFormDataGenerator());
  const formRules = reactive<FormRules>({
    phoneNumber: [
      {
        validator: (rule: FormItemRule, value: string) => {
          if (!value) {
            return new Error('手机号码不能为空');
          }
          if (!isCnMobile(value)) {
            return new Error('手机号码格式不正确');
          }
        },
        trigger: ['input', 'blur'],
      },
    ],
    password: [
      {
        validator: (rule: FormItemRule, value: string) => {
          if (!value) {
            return new Error('密码不能为空');
          }
        },
        trigger: ['blur'],
      },
    ],
    captcha: [
      {
        validator: (rule: FormItemRule, value: string) => {
          if (!value) {
            return new Error('验证码不能为空');
          }
        },
        trigger: ['blur'],
      },
    ],
  });

  const onlyAllowNumber: (value: string) => boolean = (value) => !value || /^\d+$/.test(value);
  const initPage = () => {
    if (activeTabName.value === 'qrcodeLogin' && timer === null) {
      getQr();
    }
  };
  const onTabChange: (tabName: string | number) => void = (tabName) => {
    if (tabName === 'qrcodeLogin') {
      qrSrc.value = '';
      getQr();
    } else if (tabName === 'accountLogin') {
      stopPollQrCheck();
    }
  };
  const getQr = async () => {
    await getQrKey();
    await getQrSrc();
    // 初始化查询一次qrCheckCode
    qrCheckCode.value === 0 && (await pollQrCheck());
    if (qrSrc.value) {
      timer = setInterval(async () => await pollQrCheck(), 4000);
    }
  };
  const getQrKey = async () => {
    const [error, resp] = await $to(loginApi.qrKey());
    if (error || resp.code !== ResultEnum.SUCCESS) {
      $message.error(resp?.msg || error?.msg || error || '');
    }
    if (resp && resp.code === ResultEnum.SUCCESS && resp.data) {
      const {
        data: { unikey },
      } = resp;
      qrKey.value = unikey;
      return;
    }
    qrKey.value = '';
  };
  const getQrSrc = async () => {
    if (!qrKey.value) {
      return;
    }
    const [error, resp] = await $to(loginApi.qrCreate(qrKey.value));
    if (error || resp.code !== ResultEnum.SUCCESS) {
      $message.error(resp?.msg || error?.msg || error || '');
    }
    if (resp && resp.code === ResultEnum.SUCCESS && resp.data) {
      const {
        data: { qrurl },
      } = resp;
      qrSrc.value = qrurl;
      return;
    }
    qrSrc.value = '';
  };
  const pollQrCheck = async () => {
    if (!qrKey.value) {
      return;
    }
    const [error, resp] = await $to(loginApi.qrCheck(qrKey.value));
    if (error || resp.code === LoginQrcodeCheckEnum.NOCOOKIE) {
      $message.error(resp?.msg || error?.msg || error || '');
    }
    if (resp && resp.code) {
      const { code, cookie } = resp;
      qrCheckCode.value = code;
      userCookie.value = cookie ?? '';
      switch (code) {
        case LoginQrcodeCheckEnum.TIMEOUT:
          break;
        case LoginQrcodeCheckEnum.WAITSCAN:
          break;
        case LoginQrcodeCheckEnum.WAITSURE:
          break;
        case LoginQrcodeCheckEnum.AUTHSUCCESS:
          qrCodeAuthorizationSuccess();
          break;
        case LoginQrcodeCheckEnum.NOCOOKIE:
          break;
      }
      return;
    }
    qrCheckCode.value = 0;
  };
  const stopPollQrCheck = () => {
    clearInterval(timer);
    timer = null;
  };
  const qrCodeAuthorizationSuccess = () => {
    stopPollQrCheck();
    const token = storage.get(ACCESS_TOKEN);
    !!token && router.replace({ path: PageEnum.BASE_MAIN });
  };
  const captchaSent = async () => {
    const [error, resp] = await $to(loginApi.captchaSent(formData.phoneNumber));
    if (error || resp.code !== ResultEnum.SUCCESS) {
      $message.error(resp?.msg || error?.msg || error || '');
    }
    if (resp && resp.code === ResultEnum.SUCCESS) {
      countdownNumber.value = 60;
      const timeId = setInterval(() => {
        countdownNumber.value -= 1;
        if (countdownNumber.value === 0) {
          clearInterval(timeId);
        }
      }, 1000);
    }
  };
  const captchaVerify = async () => {
    if (!formData.captcha) {
      return;
    }
    const [error, resp] = await $to(loginApi.captchaVerify(formData.phoneNumber, formData.captcha));
    if (error || resp.code !== ResultEnum.SUCCESS) {
      $message.error(resp?.msg || error?.msg || error || '');
    }
    if (resp && resp.code === ResultEnum.SUCCESS) {
      loginIn();
    }
  };
  const loginIn = () => {
    // @ts-ignore
    userStore.login({ phone: formData.phoneNumber, password: formData.password, md5_password: md5(formData.password) }, 'phone');
  };
  const onSignIn = () => {
    formRef.value?.validate((errors) => {
      if (!errors) {
        if (showCaptchaLogin.value) {
          captchaVerify();
          return;
        }
        loginIn();
      } else {
        console.log('errors', errors);
      }
    });
  };

  onMounted(initPage);
</script>
<style lang="scss">
  @media (min-width: 768px) {
    .app-login-page {
      background: url('@/assets/login.svg') no-repeat 50%/100%;
    }
  }

  .app-login-page {
    position: relative;
    display: flex;
    height: 100vh;
    background-color: #ecefff;

    &__login-part {
      position: absolute;
      right: 100px;
      top: 50%;
      transform: translateY(-50%);

      .n-tabs-nav-scroll-content {
        .n-tabs-wrapper {
          flex: 1;

          .n-tabs-tab-wrapper {
            flex: 1;

            .n-tabs-tab {
              flex: 1;
              justify-content: center;
            }
          }
        }

        .n-tabs-pad {
          flex-grow: 0 !important;
        }
      }

      .qr-code-wrapper {
        width: 220px;
        height: 220px;
        padding: 10px;
        border-radius: 8px;
        box-shadow:
          0 0 1px 1px rgba(28, 28, 32, 0.05),
          0px 8px 24px rgba(28, 28, 32, 0.12);
      }

      .captcha {
        font-size: 12px;
        color: rgba(37, 38, 43, 0.72);
        cursor: pointer;
      }
    }

    &__login-logo {
      margin-bottom: 40px;
      font-size: 28px;
      line-height: 1;
      font-family: '楷体', serif;
      text-align: center;

      &::before {
        content: '';
        display: inline-block;
        width: 28px;
        height: 28px;
        margin-right: 10px;
        background: url('@/assets/logo.png') no-repeat center / 100%;
        vertical-align: text-bottom;
      }
    }

    &__login-card {
      width: 400px;
      .n-card-header {
        position: relative;
        align-items: center;
        height: 40px;
        &__main {
          position: absolute;
          left: 24px;
          height: 24px;
        }

        &__extra {
          position: absolute;
          left: 50%;
          transform: translateX(-50%);
          font-size: 18px;
          font-weight: bold;
        }
      }
    }
  }
</style>
